/**
 *   Copyright (c) fanguangping. All rights reserved.
 *   The use and distribution terms for this software are covered by the
 *   Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
 *   which can be found in the file epl-v10.html at the root of this distribution.
 *   By using this software in any fashion, you are agreeing to be bound by
 * 	 the terms of this license.
 *   You must not remove this notice, or any other, from this software.
 **/
package org.jfunny.core.sys.impl.clojure;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.jfunny.core.dfa.DFA;
import org.jfunny.core.ds.Arg;
import org.jfunny.core.ds.Statement;
import org.jfunny.core.meta.Mapping;
import org.jfunny.core.meta.Namespace;
import org.jfunny.core.parser.Parser;
import org.jfunny.core.sys.SysEvalable;
import org.jfunny.core.sys.SysLoader;
import org.jfunny.core.sys.SysPreparable;

/**
 * 
 * @author fanguangping
 *
 */
public class SysFunction implements SysPreparable, SysEvalable{

	@Override
	public void prepare(Statement statement) {
		List<String> funcArgs = SysFunctionHelper.getArgContents(statement);
		
		String name = SysLoader.currentNamespace.getName() + "/" + funcArgs.get(0);
		String key = funcArgs.get(1);
		String value = "(" + name + " " + getArgListWithParen(key) + ")";
		
		if (variableArgs(key)) {
			value = "(" + name + " " + getVariableArgListWithParen(key) + ")";
			key = getVariableKey(key);
		}
		Mapping mapping = new Mapping(name, key, value, false);
		addToMap(SysLoader.MAPPINGS, SysLoader.currentNamespace, mapping);

		SysLoader.FUNCTIONS.add(name);
	}
	
	@Override
	public String eval(Statement statement) {
		List<String> funcArgs = SysFunctionHelper.getArgContents(statement);
		
		String name = funcArgs.get(0);
		String key = funcArgs.get(1);
		//String value = funcArgs.get(2);
		Statement value = SysFunctionHelper.getArg(statement, 2);

		StringBuffer buffer = new StringBuffer();
		buffer.append("(defn ");
		buffer.append(name);
		buffer.append(" [");
		//buffer.append(getArgList(key));
		if (variableArgs(key)) {
			buffer.append(getVariableArgList(key));
		}
		else {
			buffer.append(getArgList(key));
		}
		buffer.append("] ");
		
		String valueExpr = DFA.getInstance().match(null, value); //匹配并翻译value

		buffer.append(valueExpr.trim());

		buffer.append(")");

		return buffer.toString();
	}
	
	private static String getArgListWithParen(String statement) {
		StringBuffer buffer = new StringBuffer();

		List<Statement> list = Parser.parse("{" + statement + "}").getChildren();
		for (Statement s : list) {
			if (s instanceof Arg) {
				String argName = ((Arg) s).toString();
				buffer.append(argName);
				buffer.append(" ");
			}
		}

		return buffer.toString().trim();
	}
	
	private static boolean variableArgs(String statement) {
		List<Statement> list = Parser.parse("{" + statement + "}").getChildren();
		for (Statement s : list) {
			if (s instanceof Arg) {
				String argName = ((Arg) s).getContent();
				if (argName.endsWith("...")) {
					return true;
				}
			}
		}
		return false;
	}
	
	private static String getVariableKey(String statement) {
		String oldStr = null;
		String newStr = null;
		List<Statement> list = Parser.parse("{" + statement + "}").getChildren();
		for (Statement s : list) {
			if (s instanceof Arg) {
				String argName = ((Arg) s).getContent();
				if (argName.endsWith("...")) {
					oldStr = "{" + argName +"}";
					newStr = "【{" + argName.substring(0, argName.length() - 3) + "}】*";
				}
			}
		}
		
		return statement.replace(oldStr, newStr);
	}
	
	private static String getVariableArgListWithParen(String statement) {
		StringBuffer buffer = new StringBuffer();
		String variableArg = null;

		List<Statement> list = Parser.parse("{" + statement + "}").getChildren();
		for (Statement s : list) {
			if (s instanceof Arg) {
				String argName = ((Arg) s).getContent();
				if (argName.endsWith("...")) {
					variableArg = "{" + argName.substring(0, argName.length() - 3) + "}";
				}
				else {
					buffer.append("{" + argName + "}");
					buffer.append(" ");
				}
			}
		}
		buffer.append("【");
		buffer.append(variableArg);
		buffer.append("】*");
		
		return buffer.toString().trim();
	}

	// statement例如：{a}与{b}的平方和
	private static String getArgList(String statement) {
		StringBuffer buffer = new StringBuffer();

		List<Statement> list = Parser.parse("{" + statement + "}").getChildren();
		for (Statement s : list) {
			if (s instanceof Arg) {
				String argName = ((Arg) s).getContent();
				buffer.append(argName);
				buffer.append(" ");
			}
		}

		return buffer.toString().trim();
	}
	
	private static String getVariableArgList(String statement) {
		StringBuffer buffer = new StringBuffer();
		String variableArg = null;

		List<Statement> list = Parser.parse("{" + statement + "}").getChildren();
		for (Statement s : list) {
			if (s instanceof Arg) {
				String argName = ((Arg) s).getContent();
				if (argName.endsWith("...")) {
					variableArg = argName.substring(0, argName.length() - 3);
				}
				else {
					buffer.append(argName);
					buffer.append(" ");
				}
			}
		}
		buffer.append("& ");
		buffer.append(variableArg);
		
		return buffer.toString().trim();
	}

	private static void addToMap(Map<Namespace, List<Mapping>> map, Namespace namespace, Mapping mapping) {
		if (map.get(namespace) == null) {
			map.put(namespace, new ArrayList<Mapping>());
		}
		map.get(namespace).add(mapping);
	}
}
